﻿using System;
using System.Linq;
using System.Text;
using System.Web.UI;
using Microsoft.SharePoint;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.Utilities;
using System.Drawing;

namespace VPLink2013.Webpart
{
    public class EventCalendar : System.Web.UI.WebControls.Calendar, INamingContainer
    {
        public string SiteUrl
        {
            get { return _siteUrl; }
            set { _siteUrl = value; }
        }

        public string ListName
        {
            get { return _listName; }
            set { _listName = value; }
        }

        public string CalendarDateString
        {
            get { return _calendarDateString; }
            set { _calendarDateString = value; }
        }

        public string SiteRelativeEventItemUrl
        {
            get { return _siteRelativeEventItemUrl; }
            set { _siteRelativeEventItemUrl = value; }
        }

        public string OnMouseOverBackgroundColor
        {
            get { return _onMouseOverBackgroundColor; }
            set { _onMouseOverBackgroundColor = value; }
        }

        private const string AllDayEventDurationFormatString = "{0} - {1}";
        private const string EventDurationFormatString = "{0} {1} - {2} {3}";
        private const string OnMouseOverBackgoundColorFormatString = "this.style.backgroundColor='{0}'";

        private const string DefaultStyleEvent = "font-weight:bold;";
        private const string DefaultStyleOtherMonth = "color:#AAAAAA;";
        private const string DefaultStyleTodayBackrgoundColor = "#EC008C";

        private const string EventsListCamlQuery = @"
            <Where>
                <DateRangesOverlap>
                    <FieldRef Name=""EventDate"" />
                    <FieldRef Name=""EndDate"" />
                    <FieldRef Name=""RecurrenceID"" />
                    <Value Type=""DateTime""><Month /></Value>
                </DateRangesOverlap>
            </Where>
            ";

        private SPList _eventsList;
        private SPListItemCollection _eventItems;
        private SPWeb _site = null;
        private string _calendarDateString;
        private string _listName;
        private string _onMouseOverBackgroundColor;
        private string _siteRelativeEventItemUrl;
        private string _siteUrl;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if (String.IsNullOrEmpty(_listName))
            {
                _listName = "Calendar";
            }

            _site = String.IsNullOrEmpty(_siteUrl) ? SPContext.Current.Web : SPContext.Current.Site.OpenWeb(_siteUrl);

            if (_site == null)
            {
                return;
            }

            foreach (var list in _site.Lists.Cast<SPList>().Where(list => list.Title.Equals(_listName, StringComparison.InvariantCultureIgnoreCase)))
            {
                _eventsList = list;
                break;
            }

            if (_eventsList == null)
            {
                return;
            }

            DateTime calendarDate;

            if (!DateTime.TryParse(_calendarDateString, out calendarDate))
            {
                calendarDate = DateTime.Now;
            }

            _eventItems = GetEventItems(calendarDate);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.BackColor = Color.White;
        }

        protected override void OnUnload(EventArgs e)
        {
            base.OnUnload(e);

            if (!String.IsNullOrEmpty(_siteUrl) && _site != null)
            {
                _site.Close();
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (_eventsList == null)
            {
                return;
            }

            this.Attributes.Add("title", string.Empty);

            base.Render(writer);

        }

        protected override void OnVisibleMonthChanged(DateTime newDate, DateTime previousDate)
        {
            base.OnVisibleMonthChanged(newDate, previousDate);
            _eventItems = GetEventItems(newDate);
        }

        protected override void OnDayRender(TableCell cell, CalendarDay day)
        {
            cell.Controls.Clear();
            StringBuilder styleAttribute = new StringBuilder();

            if (!String.IsNullOrEmpty(_onMouseOverBackgroundColor))
            {
                cell.Attributes.Add("onmouseover",
                                    String.Format(OnMouseOverBackgoundColorFormatString, _onMouseOverBackgroundColor));
                Color backColor = GetBackColor(day);
                if (backColor == Color.Empty)
                {
                    if (day.IsToday && String.IsNullOrEmpty(this.TodayDayStyle.CssClass))
                    {
                        cell.Attributes.Add("onmouseout",
                                            String.Format(OnMouseOverBackgoundColorFormatString,
                                                          DefaultStyleTodayBackrgoundColor));
                    }
                    else
                    {
                        cell.Attributes.Add("onmouseout", String.Format(OnMouseOverBackgoundColorFormatString, ""));
                    }
                }
                else
                {
                    cell.Attributes.Add("onmouseout",
                                        String.Format(OnMouseOverBackgoundColorFormatString,
                                                      backColor.ToKnownColor()));
                }
            }

            if (day.IsToday && String.IsNullOrEmpty(this.TodayDayStyle.CssClass))
            {
                styleAttribute.Append(String.Format("background-color:{0};", DefaultStyleTodayBackrgoundColor));
            }

            if (day.IsOtherMonth && String.IsNullOrEmpty(this.OtherMonthDayStyle.CssClass))
            {
                styleAttribute.Append(DefaultStyleOtherMonth);
            }

            if (_eventsList == null || _eventItems.Count == 0)
            {
                cell.Controls.Add(new LiteralControl(day.DayNumberText));
            }
            else
            {
                if (CreateCellControls(cell, day))
                {
                    if (String.IsNullOrEmpty(this.SelectedDayStyle.CssClass))
                    {
                        styleAttribute.Append(DefaultStyleEvent);
                    }
                    else
                    {
                        cell.CssClass = this.SelectedDayStyle.CssClass;
                    }
                }
            }

            if (styleAttribute.Length > 0)
            {
                cell.Attributes.Add("style", styleAttribute.ToString());
            }

            base.OnDayRender(cell, day);
        }

        private SPListItemCollection GetEventItems(DateTime calendarDate)
        {
            SPQuery query = new SPQuery();
            query.ExpandRecurrence = true;
            query.CalendarDate = calendarDate;
            query.Query = EventsListCamlQuery;

            return _eventsList.GetItems(query);
        }

        private Color GetBackColor(CalendarDay day)
        {
            if (day.IsOtherMonth)
            {
                return this.OtherMonthDayStyle.BackColor;
            }

            if (day.IsToday)
            {
                return this.TodayDayStyle.BackColor;
            }

            return this.DayStyle.BackColor;
        }

        private bool CreateCellControls(TableCell cell, CalendarDay day)
        {
            bool allDayEvent;
            bool dayHasEvent = false;
            int itemID;
            DateTime eventStartDate;
            DateTime eventEndDate;
            HyperLink eventHyperLink;
            LiteralControl titleLabel;
            Panel eventPopUpPanel = null;
            StringBuilder eventTitle = new StringBuilder();

            foreach (SPListItem item in _eventItems)
            {
                eventStartDate = Convert.ToDateTime(item["EventDate"]);
                eventEndDate = Convert.ToDateTime(item["EndDate"]);

                if (DateTime.Compare(eventStartDate.Date, day.Date.Date) <= 0 &&
                    DateTime.Compare(day.Date.Date, eventEndDate.Date) <= 0)
                {
                    itemID = int.Parse(item["ID"].ToString());

                    if (!dayHasEvent)
                    {
                        dayHasEvent = true;
                        eventPopUpPanel = new Panel();
                        eventPopUpPanel.ID = String.Format("{0}{1}", this.UniqueID, day.Date.ToString("yyyyMMdd"));
                        eventPopUpPanel.CssClass = "balloonstyle";
                        eventPopUpPanel.Attributes.Add("rel",
                                                       (day.Date.Day.ToString() + day.Date.Month.ToString() +
                                                        day.Date.Year.ToString()));
                        titleLabel = new LiteralControl("<H3>" + day.Date.ToLongDateString() + "</H3>");
                        eventPopUpPanel.Controls.Add(titleLabel);
                        eventPopUpPanel.Controls.Add(new LiteralControl("<ul>"));
                    }

                    eventPopUpPanel.Controls.Add(new LiteralControl("<li>"));
                    eventHyperLink = new HyperLink();

                    string url = GetItemUrl(itemID);
                    eventHyperLink.NavigateUrl = "javascript:ShowCalendarEventDialog('" + url.ToString() + "');";

                    if (item["fAllDayEvent"] == null)
                    {
                        allDayEvent = false;
                    }
                    else
                    {
                        allDayEvent = Convert.ToBoolean(item["fAllDayEvent"].ToString());
                    }

                    eventHyperLink.Text = SPEncode.HtmlEncode(item["Title"].ToString());
                    eventHyperLink.ToolTip = GetEventDuration(eventStartDate, eventEndDate, allDayEvent);
                    eventPopUpPanel.Controls.Add(eventHyperLink);
                    eventPopUpPanel.Controls.Add(new LiteralControl("</li>"));
                }
            }

            if (dayHasEvent)
            {
                eventPopUpPanel.Controls.Add(new LiteralControl("</ul>"));
                HyperLink dayHyperLink = new HyperLink();
                dayHyperLink.Text = day.DayNumberText;
                dayHyperLink.NavigateUrl = "javascript:showEvents(" + day.Date.Day.ToString() +
                                           day.Date.Month.ToString() + day.Date.Year.ToString() + ");";
                dayHyperLink.CssClass = "balloontrigger";

                Panel eventPanel = new Panel();
                eventPanel.CssClass = "balloonContainer";
                eventPanel.Controls.Add(dayHyperLink);
                eventPanel.Controls.Add(eventPopUpPanel);
                cell.Controls.Add(eventPanel);
            }
            else
            {
                cell.Controls.Add(new LiteralControl(day.DayNumberText));
            }

            return dayHasEvent;
        }

        private string GetItemUrl(int itemID)
        {
            string siteRelativeEventUrl;
            int formNb = (int)PAGETYPE.PAGE_DISPLAYFORM;

            if (_eventsList.Forms.Count <= formNb)
                formNb = 0;

            if (String.IsNullOrEmpty(_siteRelativeEventItemUrl))
            {
                siteRelativeEventUrl = _eventsList.Forms[formNb].Url;
            }
            else
            {
                siteRelativeEventUrl = _siteRelativeEventItemUrl.TrimStart("/".ToCharArray());
            }

            return String.Format("../{0}?ID={1}", siteRelativeEventUrl, itemID);
        }

        private string GetEventDuration(DateTime startDateTime, DateTime endDateTime, bool allDayEvent)
        {
            if (DateTime.Compare(startDateTime.Date, endDateTime.Date) == 0)
            {
                if (allDayEvent)
                {
                    return "All Day";
                }
                else
                {
                    return String.Format(AllDayEventDurationFormatString, startDateTime.ToShortTimeString(),
                                         endDateTime.ToShortTimeString());
                }
            }

            if (allDayEvent)
            {
                return String.Format(AllDayEventDurationFormatString, startDateTime.ToShortDateString(),
                                     endDateTime.ToShortDateString());
            }
            else
            {
                return String.Format(EventDurationFormatString, startDateTime.ToShortDateString(),
                                     startDateTime.ToShortTimeString(), endDateTime.ToShortDateString(),
                                     endDateTime.ToShortTimeString());
            }
        }
    }
}
